/*******************************************************************************
 * Copyright (c) 2011 Alexandru Burdusel. All rights reserved. This program
 * and the accompanying materials are made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution, and is
 * available at http://www.eclipse.org/legal/epl-v10.html
 * 
 *******************************************************************************/
package org.topcased.uml2qos.services;

import java.util.regex.*;

/**
 * UML QoS Services
 * 
 * @author Alexandru Burdusel
 */
public class UmlQosServices
{
	/**
	 * Takes the method name with QoS constraints as argument
	 * and returns the method name without constrains
	 * 
	 * @param methodName
	 * @return method name without constraints
	 */
    public String removePreArguments(String methodName)
    {
    	
    	String[] newMethodName = Pattern.compile("[\\[*\\]]").split(methodName);
    	if(newMethodName.length > 0){
    		return newMethodName[0];
    	} else {
    		return methodName;
    	}
    }
    
    /**
     * Takes the method as argument
     * and returns true if the method contains QoS constraints
     * @param methodName
     * @return boolean
     */
    public boolean hasPreArguments(String methodName)
    {	
    	
		Pattern pattern = Pattern.compile("[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*+\\[+.+\\]");
		Matcher matcher = pattern.matcher(methodName);
		
		if(matcher.matches()){
			return true;
		}else{
			return false;
		}
    }
    
    /**
     * Returns the QoS constraints from a given method name
     * No need to check if the QoS constraints exist, a check is aleady made
     * before the method call
     * @param methodName
     * @return String[]
     */
    public String getPreArguments(String methodName)
    {
    	
   	 	String[] newMethodName = Pattern.compile("[\\[*\\]]").split(methodName);
   	 	if(newMethodName.length == 2){
   	 		return newMethodName[1];
   	 	} else {
   	 		return "";
   	 	}
    }

    /**
     * Checks if the completion time constraint is valid
     * @param completionTimeConstraint
     * @return boolean
     */
    public boolean hasValidCompletionTimeConstraint(String completionTimeConstraint)
    {
    	
		Pattern pattern = Pattern.compile("ct+(<|>)+\\d{1,10}+\\.{0,1}+\\d{0,6}");
		Matcher matcher = pattern.matcher(completionTimeConstraint);
		
		//If the check for < fails, we definitely have >
		if(matcher.matches()){
			return true;
		}else{
			return false;
		}
	}
    
    /**
     * Returns the completion time method arguments for the given constraint.
     * A constraint is composed of type, logical operator and QoS value in seconds
     * Example: ct>0.005
     * @param completionTimeConstraint
     * @return String
     */
	public String makeCompletionTimeMethodArguments(String completionTimeConstraint){
		
		StringBuffer completionTimeParameters = new StringBuffer("");
		
		//Make sure all spaces are removed
		completionTimeConstraint = StringServices.removeSpaces(completionTimeConstraint);
		
		//The expression has been checked before this, to see if it contains > or <
		
		String qosValue = getQosValue(completionTimeConstraint);
		String logicalOperator = getLogicalOperator(completionTimeConstraint);	

		completionTimeParameters.append("__CLASS__ . \"::\" . __FUNCTION__, '" + qosValue + "', '"+ logicalOperator + "'");
		
    	return completionTimeParameters.toString();
    }
	
	/**
	 * Get the QoS value from the QoS constraint
	 * @param String
	 * @return the completion time constraint
	 */
	public String getQosValue(String completionTimeConstraint){
		
    	String[] constraintsArray = Pattern.compile(getLogicalOperator(completionTimeConstraint)).split(completionTimeConstraint);
    	if(constraintsArray.length == 2)
    	{
    		//Return the second value from the array
    		return constraintsArray[1];
    	} else {
    		return "";
    	}
	}
	
	/**
	 * Get the logical operator from the QoS constraint
	 * @param String
	 * @return completion time logical operator
	 */
	public String getLogicalOperator(String completionTimeConstraint)
	{
		Pattern pattern = Pattern.compile("ct+<+\\d{1,10}\\.{0,1}\\d{0,6}");
		Matcher matcher = pattern.matcher(completionTimeConstraint);
		
		//If the check for < fails, we definitely have >
		if(matcher.matches()){
			return "<";
		}else{
			return ">";
		}
	}
	
    /**
     * Returns the QoS constraints as an array
     * @param constraints
     * @return All constraints in an array
     */
    public String[] qosConstraints(String constraints)
    {
    	String[] constraintsArray = Pattern.compile(",").split(constraints);
    	
    	return constraintsArray;
    }
    
    /**
     * Returns the advice method content. The content is based on the
     * QoS constraints set as prearguments for the method to be instrumented.
     * @param methodName
     * @return String
     */
    public String generateQosCode(String methodName)
    {
    	//Duplication checkers
    	boolean hasPutCompletionTime = false;
    	boolean hasPutArrivalRate = false;
    	boolean hasPutAccessibility = false;
    	boolean hasPutThroughput = false;
    	
    	methodName = StringServices.removeSpaces(methodName);
    	
    	String constraints = getPreArguments(methodName);
    	
    	//If no constraints are found
    	if(constraints.length() == 0){
    		return "";
    	}
    	
    	//Remove the straight brackets
    	Pattern straightBrackets = Pattern.compile("[\\[|\\]]");
        Matcher m = straightBrackets.matcher(constraints); 
        constraints = m.replaceAll("");
    	String[] qosConstraints = Pattern.compile(",").split(constraints);
    	
    	//Put everything in a string buffer and make sure there is no duplication
    	StringBuffer qosMethodDefinition = new StringBuffer("\n");

    	for(int i=0;i<qosConstraints.length;i++){
    		
    		if(qosConstraints[i].matches("ar") && !hasPutArrivalRate){
    			
    			qosMethodDefinition.append(StringServices.addTab(1) + 
    					"$arrivalRate = new ArrivalRate(__CLASS__ . '::' . __FUNCTION__);" + "\n");
    			
    			hasPutArrivalRate = true;
    		}
    		
    		if(qosConstraints[i].matches("acc") && !hasPutAccessibility){
    			
    			qosMethodDefinition.append(StringServices.addTab(1) + 
    					"$accessibility = new Accessibility(__CLASS__ . '::' . __FUNCTION__);" + "\n");
    			
    			hasPutAccessibility = true;
    		}
    		
    		if(qosConstraints[i].matches("thp") && !hasPutThroughput){
    			
    			qosMethodDefinition.append(StringServices.addTab(1) + 
    					"$throughput = new Throughput(__CLASS__ . '::' . __FUNCTION__);" + "\n");
    			
    			hasPutThroughput = true;
    		}
    		
    		if(hasValidCompletionTimeConstraint(qosConstraints[i]) && !hasPutCompletionTime){
    			
    			qosMethodDefinition.append(StringServices.addTab(1) + 
    					"$completionTime = new CompletionTime("+ makeCompletionTimeMethodArguments(qosConstraints[i]) +");" + "\n");
    			
    			hasPutCompletionTime = true;  			
    		}
    		
    	}
    	
    	return qosMethodDefinition.toString();
    	
    }
    
}
